#include "QPropertyModel.h"

#include <QBrush>
#include "QPropertySet.h"

using namespace QPE;

#include "private/QPropertyModel_p.h"

QPropertyModel::QPropertyModel(QPropertyModelPrivate *d, QObject *parent)
	: QAbstractItemModel(parent), d_ptr(d)
{
}


QPropertyModel::QPropertyModel(QObject * parent) :
	QAbstractItemModel(parent), d_ptr(new QPropertyModelPrivate())
{
}

QPropertyModel::~QPropertyModel()
{
	if(d_ptr->Properties)
		delete d_ptr->Properties;

	delete d_ptr;
}

//! Adds the property to the model and attaches it to the parentid
bool QPropertyModel::addProperty(QProperty* property, const QString& id, const QString &parentid, bool emitsignals)
{
	if(!property)
		return false;

	if(!d_ptr->Properties)	// If not existant, create property set
		d_ptr->Properties = new QPropertySet();

	if(emitsignals) {
		QProperty* tmpParent = getProperty(parentid);
		int tmpRow = tmpParent != NULL ? tmpParent->getRowCount() : d_ptr->Properties->getRootPropertyCount();
		beginInsertRows((tmpParent != NULL ? getIndexFromProperty(tmpParent) : QModelIndex()), tmpRow, tmpRow);
	}

	d_ptr->Properties->addProperty(property, id, parentid);

	if(emitsignals)
		endInsertRows();

	return true;

}

//! Creates a property and adds it to the model
QProperty* QPropertyModel::createProperty(const QString& id, const QString& name, const QString& parentid, const QVariant& data)
{
	QProperty* tmpProp = new QProperty(name);
	tmpProp->setValue(data);
	if(tmpProp && addProperty(tmpProp, id, parentid))
		return tmpProp;
	else
		return NULL;
}

//! Gets a property by it's ID
QProperty* QPropertyModel::getProperty(const QString& id)
{
	return d_ptr->Properties != NULL ? d_ptr->Properties->getProperty(id) : NULL;
}



//! Returns the model index at row/column
QModelIndex QPropertyModel::index(int row, int column, const QModelIndex& parent) const
{
	if (d_ptr->Properties == NULL || (parent.isValid() && parent.column() > 1))
			return QModelIndex();

	if(parent.isValid()) {
		// Get the parent index
		QProperty* parentItem = getProperty(parent);
		if(parentItem) {
			QProperty* childItem = parentItem->getChild(row);
			if (childItem)
				return createIndex(row, column, childItem);
		}
	} else if(row >= 0 && row < d_ptr->Properties->count()) {
		return createIndex(row, column, d_ptr->Properties->getRootProperty(row));
	}

	return QModelIndex();
}

//! Returns the parent of one model index
QModelIndex QPropertyModel::parent ( const QModelIndex & index ) const
{
	if (!index.isValid())
		return QModelIndex();

	QProperty* childItem = getProperty(index);
	if(childItem) {
		QProperty* parentItem = childItem->getParent();
		if(parentItem) {
			QProperty* grandParentItem = parentItem->getParent();
			int parents_row = grandParentItem != NULL ? grandParentItem->getChildRow(parentItem) : d_ptr->Properties->getRootProperties().indexOf(parentItem);

			if(parents_row >= 0)
				return createIndex(parents_row, 0, parentItem);
		}
	}

	return QModelIndex();
}

//! Returns the item flags for the given index
Qt::ItemFlags QPropertyModel::flags (const QModelIndex& index) const
{
	QProperty* tmpProperty = getProperty(index);
	if(!tmpProperty)
		return Qt::NoItemFlags;
	else
		return tmpProperty->flags(index.column());
}

//! Sets the role data for the item at index to value
bool QPropertyModel::setData (const QModelIndex& index, const QVariant& value, int role)
{
	QProperty* tmpProperty = getProperty(index);
	if(index.column() == 1 && tmpProperty) {
		bool tmpHasChanged = tmpProperty->setData(value, role);
		if(tmpProperty->getUpdateParent() && tmpHasChanged) {	// If neccessary, update the parent as well
			QModelIndex tmpParentIndex = parent(index);
			emit dataChanged(tmpParentIndex, tmpParentIndex);
		}

		if(tmpHasChanged)
			emit onDataChangedByEditor(tmpProperty);
	}


	return true;
}


//! Returns the data of an model index
QVariant QPropertyModel::data ( const QModelIndex & index, int role ) const
{
	QProperty* tmpProperty = getProperty(index);
	if(!tmpProperty)
		return QVariant();
	else
		return tmpProperty->data(index.column(), role);
}


QVariant QPropertyModel::headerData (int section, Qt::Orientation orientation, int role) const
{
	if(orientation == Qt::Horizontal && role == Qt::DisplayRole) {
		// Header data
		if (section == 0) return d_ptr->HeadlineProperty;
		else if (section == 1) return d_ptr->HeadlineValue;
	}
	else if(role == Qt::DisplayRole)
		return QVariant(section);

	return QVariant();
}


//! Returns the number of rows
int QPropertyModel::rowCount ( const QModelIndex & parent ) const
{
	if(parent.isValid()) {
		QProperty* tmpParent = getProperty(parent);
		if(tmpParent)
			return tmpParent->getRowCount();
	}

	// Return the root property count
	if(d_ptr->Properties)
		return d_ptr->Properties->getRootPropertyCount();

	return 0;
}


//! Returns the number of columns
int QPropertyModel::columnCount ( const QModelIndex & parent) const
{
	Q_UNUSED(parent);
	return 2;
}


//! Gets a property by its ModelIndex
QProperty* QPropertyModel::getProperty(const QModelIndex &index) const
{
	if (index.isValid()) {
		QProperty* prop = static_cast<QProperty*>(index.internalPointer());

		if (prop)
			return prop;
	}
	return NULL;
}

QString QPropertyModel::getPropertyID(QProperty *prop) const
{
	return d_ptr->Properties != NULL ? d_ptr->Properties->getPropertyID(prop) : QString();
}

QModelIndex QPropertyModel::getIndexFromProperty(QProperty* property, int column) const
{
	if (!property || column > columnCount() || column < 0)
			return QModelIndex();

	QProperty* parentItem = property->getParent();
	int row = 0;

	if(parentItem) {
		row = parentItem->getChildRow(property);
	}

	return createIndex(row, column, property);
}


void QPropertyModel::onDataChangedByModel(QProperty* property)
{
	QModelIndex tmpIndex = getIndexFromProperty(property, 1);
	if(tmpIndex.isValid())
		emit dataChanged(tmpIndex, tmpIndex);

}

const QPropertySet *QPropertyModel::getPropertySet() const
{
	return d_ptr->Properties;
}

void QPropertyModel::clear(bool emit_signals)
{
	setPropertySet(NULL, emit_signals);
}

QPropertySet *QPropertyModel::takePropertySet(QPropertySet *new_property_set, bool emit_signals)
{
	QPropertySet* tmpOldPropertySet = d_ptr->Properties;

	if(emit_signals) emit beginResetModel();
	d_ptr->Properties = new_property_set;
	if(emit_signals) emit endResetModel();

	return tmpOldPropertySet;
}

void QPropertyModel::setPropertySet(QPropertySet *property_set, bool emit_signals)
{
	QPropertySet* tmpOldPropertySet = takePropertySet(property_set, emit_signals);
	if(tmpOldPropertySet)
		delete tmpOldPropertySet;
}

QProperty *QPropertyModel::takeProperty(const QString &id)
{
	QModelIndex tmpIndex = getIndexFromProperty(getProperty(id));
	if(d_ptr->Properties && tmpIndex.isValid()) {
		beginRemoveRows(tmpIndex.parent(), tmpIndex.row(), tmpIndex.row());
		QProperty* tmpProp = d_ptr->Properties->takeProperty(id);
		endRemoveRows();
		return tmpProp;
	}

	return NULL;
}

void QPropertyModel::removeProperty(const QString &id)
{
	QModelIndex tmpIndex = getIndexFromProperty(getProperty(id));
	if(d_ptr->Properties && tmpIndex.isValid()) {
		beginRemoveRows(tmpIndex.parent(), tmpIndex.row(), tmpIndex.row());
		d_ptr->Properties->removeProperty(id);
		endRemoveRows();
	}
}
